<?php
/**
 * @author MarcusM. works for huike. QQ:2453302174
 */
class WxInterface extends CApplicationComponent
{
    use BasicTrait;

    protected static $_NOW = 0;

    protected $_wxplatform = null;

    protected $_curl;
    protected function _cInit()
    {
        $this->_curl = curl_init();
        curl_setopt($this->_curl, CURLOPT_HTTPHEADER, array(
            "content-type: application/x-www-form-urlencoded; charset=UTF-8"
        ));
        curl_setopt($this->_curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($this->_curl, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($this->_curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($this->_curl, CURLOPT_CONNECTTIMEOUT_MS, 5000);
        curl_setopt($this->_curl, CURLOPT_TIMEOUT_MS, 5000);
    }

    public function __destruct()
    {
        curl_close($this->_curl);
    }


    public function redisSet($key, $value)
    {
        $key = 'Wxplatform:' . $this->_wxplatform->id_wxplatform . ':' . $key;
        return app()->redis->set($key, $value);
    }

    public function redisSetex($key, $timeout, $value)
    {
        $key = 'Wxplatform:' . $this->_wxplatform->id_wxplatform . ':' . $key;
        return app()->redis->setex($key, $timeout, $value);
    }

    public function redisGet($key)
    {
        $key = 'Wxplatform:' . $this->_wxplatform->id_wxplatform . ':' . $key;
        return app()->redis->get($key);
    }

    public function switchPlatform($wxplatform = null)
    {
        if(empty($wxplatform)){
            $this->_wxplatform = Wxplatform::getDefaultPlatform();
        }elseif(is_numeric($wxplatform)){
            $this->_wxplatform = Wxplatform::model()->findByPk($wxplatform);
        }else{
            $this->_wxplatform = $wxplatform;
        }
    }

    public function getWxplatform()
    {
        return $this->_wxplatform;
    }

    public function init()
    {
        self::$_NOW = time();
        $this->_cInit();

        return parent::init();
    }

    protected function _runCurl($baseReq, $reqFields)
    {
        $url = empty($reqFields)? $baseReq : $baseReq . '?' . http_build_query($reqFields);
        curl_setopt($this->_curl, CURLOPT_URL, $url);
//		curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $reqFields);
        $ret = curl_exec($this->_curl);

        return $ret;
    }

    protected function _runPostCurl($baseReq, $reqFields)
    {
        $url = $baseReq;
        curl_setopt($this->_curl, CURLOPT_URL, $url);
        curl_setopt($this->_curl, CURLOPT_POST, 1);
        curl_setopt($this->_curl, CURLOPT_POSTFIELDS, json_encode($reqFields, JSON_UNESCAPED_UNICODE));
        $ret = curl_exec($this->_curl);

        return $ret;
    }

    public function saveOauth2State($state)
    {
        $stateKey = 'OauthState:' . microtime(true) . '_' . rand(0, 999999);
        if(app()->redis->setex($stateKey, 120, json_encode($state))){
            return $stateKey;
        }else{
            return false;
        }
    }

    public function getOauth2State($stateKey)
    {
        $value = app()->redis->get($stateKey);
        return json_decode($value);
    }

    public function oAuthLogin($redirect_uri, $state, $response_type = 'code', $scope = 'snsapi_base')
    {
        //$scope = 'snsapi_base';
        //$scope = 'snsapi_userinfo';

        $redirect_uri = urlencode($redirect_uri);
        $state = $this->saveOauth2State($state);
        $authUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->_wxplatform->appid}&redirect_uri={$redirect_uri}&response_type={$response_type}&scope={$scope}&state={$state}#wechat_redirect";
        return app()->request->redirect($authUrl);
    }



    public function getUserInfo($access_token, $openid, $lang = 'zh_CN')
    {
        $retUserInfo = $this->_runCurl('https://api.weixin.qq.com/sns/userinfo', array(
            'access_token' => $access_token,
            'openid' => $openid,
            'lang' => $lang,
        ));
        $retUserInfo = json_decode($retUserInfo);
        return $retUserInfo;
    }


    public function getMedia($media_id)
    {
        $ret = false;
        $cgiAccessToken = $this->getCgibinAccessToken('client_credential')->access_token;
        if(!isset($retAccessToken->errcode)){
            $i = 6;
            while($i--){
                sleep(1);

                $ret = $this->_runCurl('http://file.api.weixin.qq.com/cgi-bin/media/get', array(
                    'access_token' => $cgiAccessToken,
                    'media_id' => $media_id,
                ));
                if($ret === false){		// net break
                    continue;
                }
                $retDe = json_decode($ret);
                if(empty($retDe)){
                    return $ret;
                    break;
                }
            }
        }

        return false;
    }






    public function getOauth2AccessToken($code)
    {
        $ret = $this->_runCurl(app()->params['FRONTEND_BASEURL'] . '/wxhelper/GetOauth2AccessToken', array(
            'appid' => $this->_wxplatform->appid,
            'appsecret' => $this->_wxplatform->appsecret,
            'code' => $code
        ));

        $ret = json_decode($ret);

        return $ret;
    }

    const CGIBIN_ACCESS_TOKEN_KEY_CACHE = 'CGIBIN_ACCESS_TOKEN_KEY_CACHE';

    public function getCgibinAccessToken($refresh = false)
    {

        $accessToken = $this->_runCurl(app()->params['get_cgi_token'].'/wxhelper/GetCgibinAccessToken', array(
            'appid' => $this->_wxplatform->appid,
            'appsecret' => $this->_wxplatform->appsecret,
            'grant_type' => 'client_credential',
            'refresh' => $refresh,
            'from' => 'Myself'
        ));

        return json_decode($accessToken);
    }


    public function getCardApiTicket($refresh = false)
    {
        $ret = $this->_runCurl(app()->params['FRONTEND_BASEURL'] . '/wxhelper/GetCardApiTicket', array(
            'appid' => $this->_wxplatform->appid,
            'appsecret' => $this->_wxplatform->appsecret,
        ));
        $ret = json_decode($ret);

        return $ret;
    }

    public function getCgibinUserInfo( $openid, $lang = 'zh_CN')
    {
        $cgiAccessToken = $this->getCgibinAccessToken()->access_token;
        $ret = $this->_runCurl('https://api.weixin.qq.com/cgi-bin/user/info', array(
            'access_token' => $cgiAccessToken,
            'openid' => $openid,
            'lang' => $lang
        ));
        $ret = json_decode($ret);

        return $ret;
    }

    public function sendTemplateMessage($data)
    {
        $cgiAccessToken = $this->getCgibinAccessToken()->access_token;

        $oldCurlOptPost = curl_getinfo($this->_curl, CURLOPT_POST);

        curl_setopt($this->_curl, CURLOPT_POST, 1);
        curl_setopt($this->_curl, CURLOPT_POSTFIELDS, urldecode(urlencode(json_encode(($data)))));
        $ret = $this->_runCurl('https://api.weixin.qq.com/cgi-bin/message/template/send', array(
            'access_token' => $cgiAccessToken
        ));
        $ret = json_decode($ret);

        curl_setopt($this->_curl, CURLOPT_POST, $oldCurlOptPost);
        return $ret;
    }

    function formatBizQueryParaMap($paraMap, $urlencode)
    {
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v)
        {
            if($urlencode)
            {
                $v = urlencode($v);
            }
            //$buff .= strtolower($k) . "=" . $v . "&";
            $buff .= $k . "=" . $v . "&";
        }

        if (strlen($buff) > 0)
        {
            $reqPar = substr($buff, 0, strlen($buff)-1);
        }
        return $reqPar;
    }

    /**
     * 	作用：生成签名
     */
    public function getSign($Obj, $key)
    {
        foreach ($Obj as $k => $v)
        {
            if($k != 'key'){
                $Parameters[$k] = $v;
            }
        }
        //签名步骤一：按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //echo '【string1】'.$String.'</br>';

        //签名步骤二：在string后加入KEY
        if(empty($key)){
            $String = $String."&key=".WxPayConf_pub::KEY;
        }else{
            $String = $String."&key=".$key;
        }

        //echo "【string2】".$String."</br>";
        //签名步骤三：MD5加密
        $String = md5($String);
        //echo "【string3】 ".$String."</br>";
        //签名步骤四：所有字符转为大写
        $result_ = strtoupper($String);
        //echo "【result】 ".$result_."</br>";
        return $result_;
    }

    public function postXmlCurl($xml,$url,$second=30)
    {
        //初始化curl
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        //这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        curl_close($ch);
        //返回结果
        if($data)
        {
            //curl_close($ch);
            return $data;
        }
        else
        {
            $error = curl_errno($ch);
            echo "curl出错，错误码:$error"."<br>";
            echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
            curl_close($ch);
            return false;
        }
    }

    function postXmlSSLCurl($xml,$url,$second=30)
    {
        $ch = curl_init();
        //超时时间
        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
        //这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
        //设置header
        curl_setopt($ch,CURLOPT_HEADER,FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
        //设置证书
        //使用证书：cert 与 key 分别属于两个.pem文件
        //默认格式为PEM，可以注释
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLCERT, '/home/marcus/lnmp/nginx/html/payview/repository/protected/components/apiclient_cert.pem');
        //默认格式为PEM，可以注释
        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLKEY, '/home/marcus/lnmp/nginx/html/payview/repository/protected/components/apiclient_key.pem');
        //post提交方式
        curl_setopt($ch,CURLOPT_POST, true);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);

        $data = curl_exec($ch);
        //返回结果
        if($data){
            curl_close($ch);
            return $data;
        }
        else {
            $error = curl_errno($ch);
            echo "curl出错，错误码:$error"."<br>";
            echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
            curl_close($ch);
            return false;
        }
    }

    function createXml($arr)
    {
        $xml = "<xml>";
        foreach ($arr as $key=>$val)
        {
            if (is_numeric($val))
            {
                $xml.="<".$key.">".$val."</".$key.">";

            }
            else
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
        }
        $xml.="</xml>";
        return $xml;
    }

    public function sendredpack()
    {
        $data = array(
            'nonce_str' => 'rp' . rand(100000, 9099999),
            'mch_billno' => 'rpmb' . rand(100000, 9099999),
            'mch_id' => '1244330502',
            'wxappid' => 'wx30890185ab1ebb6e',
            'send_name' => 'aaa',
            're_openid' => 'oYAOQs7KqatxoldkkfAuN8LhUtxQ',
            'total_amount' => 100,
            'total_num' => 1,
            'wishing' => 'wish',
            'client_ip' => '127.0.0.1',
            'act_name' => 'act',
            'remark' => 'remark',
            'scene_id' => 'PRODUCT_1',
        );
        $data['sign'] = $this->getSign($data, 'WAKA18158100918waka18158100918FF');

        $xml = $this->createXml($data);

        $response = $this->postXmlSSLCurl($xml, 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack', 10);

        var_dump(htmlspecialchars($response));
    }

    public function menuCreate($data)
    {
// 		$data = array(
// 			'button' => array(
// 				array(
// 					'type' => 'view', 
// 					'name' => '会员卡', 
// 					'url' => 'http://slebc.waka6.com/wxuser/mymcards'
// 				), 
// 				array(
// 					'type' => 'view', 
// 					'name' => '有赞商城', 
// 					'url' => 'https://kdt.im/2U5Bnr'
// 				)
// 			)
// 		);



        $cgiAccessToken = $this->getCgibinAccessToken()->access_token;

        $oldCurlOptPost = curl_getinfo($this->_curl, CURLOPT_POST);

        curl_setopt($this->_curl, CURLOPT_POST, 1);
        curl_setopt($this->_curl, CURLOPT_POSTFIELDS, urldecode(urlencode(json_encode($data, JSON_UNESCAPED_UNICODE))));
        $ret = $this->_runCurl('https://api.weixin.qq.com/cgi-bin/menu/create', array(
            'access_token' => $cgiAccessToken
        ));var_dump($ret);
        $ret = json_decode($ret);

        curl_setopt($this->_curl, CURLOPT_POST, $oldCurlOptPost);
        return $ret;
    }

    public function checkSubscribed($openid)
    {
        $userInfoOnWx = $this->getCgibinUserInfo($openid);

        if(empty($userInfoOnWx->subscribe) || $userInfoOnWx->subscribe != 1){
            return false;
        }

        return true;
    }

    public function getCgibinTicket($refresh = false)
    {
        $ret = $this->_runCurl(app()->params['FRONTEND_BASEURL'] . '/wxhelper/GetCgibinTicket', array(
            'appid' => $this->_wxplatform->appid,
            'appsecret' => $this->_wxplatform->appsecret,
        ));

        $ret = json_decode($ret);

        return $ret;
    }


    public $signature = '';
    public $wx_noncestr = '';
    public $wx_timestamp = '';
    public $wx_url = '';
    public function initWxJsConfig($jsApiList = array(), $render = true, $withScriptTag = false, $signType = 'sha1', $nonceStr = null, $timestamp = null)
    {
        $this->wx_noncestr = $nonceStr? $nonceStr : str_shuffle('abcdefghijklmnopqrstuvwxyz');
        $this->wx_timestamp = $timestamp? $timestamp : self::$_NOW;

        //$ticket = $this->getCgibinTicket(true)->ticket;
        $ticket = $this->getCgibinTicket()->ticket;

        $this->wx_url = app()->request->hostInfo . app()->request->getUrl();

        $str = "jsapi_ticket={$ticket}&noncestr={$this->wx_noncestr}&timestamp=".$this->wx_timestamp."&url={$this->wx_url}";

        if($signType == 'sha1'){
            $this->signature = sha1($str);
        }else{
            $this->signature = md5($str);
        }

        $initParam = array(
            'debug' => false,
            'appId' => $this->_wxplatform->appid,
            'timestamp' => $this->wx_timestamp,
            'nonceStr' => $this->wx_noncestr,
            'signature' => $this->signature,
            'jsApiList' => $jsApiList
        );

        $initStr = '
			wx.config('.
            json_encode($initParam)
            .');
		';
        if($withScriptTag){
            $initStr = '<script>'.$initStr.'</script>';
        }

        if($render){
            echo $initStr;
        }else{
            return $initStr;
        }
    }

    public function getUserRHashKey($id_wxuser)
    {
        return 'USER_RHASH_MERCHANT_PLATFORM_' . $id_wxuser;
    }
}